#include <stdlib.h>
#include <stdio.h>
#include "list.h"

SList *slist_create(Pointer data)
{
    SList *list;
    list=(SList*)malloc(sizeof(SList));
    list->data=data;
    list->next=NULL;
    return list;
}

SList *slist_append(SList *list, Pointer data)
{
    SList* curlist;
	SList* newlist;
	curlist=list;
    newlist=(SList*)malloc(sizeof(SList));
    newlist->data=data;
	newlist->next=NULL;
    while (curlist->next!=NULL)
    {
        curlist=curlist->next;
    }
    curlist->next=newlist;
    return list;
}

SList *slist_prepend(SList *list, Pointer data)
{
	SList* newlist;
    newlist=(SList*)malloc(sizeof(SList));
    newlist->data=data;
    newlist->next=list;
    return newlist;
}

void slist_insert(SList *sibling, Pointer data)
{
	SList* newlist;
	newlist=(SList*)malloc(sizeof(SList));
	newlist->data=data;
	newlist->next=sibling->next;
	sibling->next=newlist;
}

SList *slist_remove(SList *list, int number)
{
	int i;
	SList* curlist;
	SList* buflist;
	curlist=list;
	if(number==1)
	{
		curlist=curlist->next;
		free(list);
		list=curlist;
	}
	else
	{
		for(i=0; i<number-1; i++)
		{
			curlist=curlist->next;
		}
		buflist=curlist;
		curlist=curlist->next;
		free(buflist);
	}
	return list;
}

SList *slist_remove_all(SList *list, Pointer data)
{
	int i;
	SList* curlist;
	SList* buflist;
	curlist=list;
	for(i=0; curlist!=NULL; i++)
	{
		if(i==0 && curlist->data==data)
		{
			curlist=curlist->next;
			free(list);
			list=curlist;
		}
		if(curlist->data==data)
		{
			buflist=curlist;
			curlist=curlist->next;
			free(buflist);
		}
		curlist=curlist->next;
	}
	return list;
}

Pointer slist_remove_next(SList *sibling)
{
	Pointer output;
	SList* buflist;
	SList* list_to_delete;
	buflist=sibling->next;
	output=buflist->data;
	list_to_delete = buflist;
	buflist=buflist->next;
	free(list_to_delete);
	return output;
}

void slist_free(SList *list)
{
	SList* buflist;
	while(list!=0)
	{
		buflist=list;
		list=list->next;
		free(buflist);
	}
	free(list);
}

unsigned slist_length(SList *list)
{
	unsigned int i;
	for(i=0; list!=0; i++)
	{
		list=list->next;
	}
	return i;
}

SList *slist_reverse(SList *list)
{
	SList* curlist;
	SList* buflist;
	SList* buflist2;
	list->next=NULL;
	buflist=list;
	curlist=buflist->next;
	while(curlist->next!=NULL)
	{
		buflist2=buflist;
		buflist=curlist;
		buflist->next=buflist2;
		curlist=curlist->next;
		curlist->next=buflist;
	}
	return curlist;
}

SList *slist_concat(SList *list1, SList *list2)
{
	SList *curlist;
	curlist=list1;
	while(curlist->next!=NULL)
	{
		curlist=curlist->next;
	}
	curlist->next=list2;
	return list1;
}

void slist_foreach(SList *list, void (*func)(Pointer data, Pointer user_data), Pointer user_data)
{
	while(list!=NULL)
	{
		func(list->data, user_data);
		list=list->next;
	}
}

SList *slist_last(SList *list)
{
	while(list->next!=NULL)
	{
		list=list->next;
	}
	return list;
}

SList *slist_nth(SList *list, int n)
{
	int i;
	if(n>0)
	{
		for(i=0; i<n-1; i++)
		{
			list=list->next;
		}
		return list;
	}
	if(n<0)
	{
		n=slist_length(list)+n;
		for(i=0; i<n-1; i++)
		{
			list=list->next;
		}
		return list;
	}
}

SList *slist_find(SList *list, Pointer needle)
{
	while(list!=NULL)
	{
		if(list->data==needle)
		{
			return list;
		}
		list=list->next;
	}
	return NULL;
}

SList *slist_find_custom(SList *list, Pointer needle, int (*compare_func)(Pointer a, Pointer b))
{
	while(list!=NULL)
	{
		if(compare_func(list->data, needle)==0)
		{
			return list;
		}
		list=list->next;
	}
}

int slist_position(SList *list, SList *el)
{
	int i;
	for(i=1; list!=NULL; i++)
	{
		if(list==el)
		{
			return i;
		}
	}
	return -1;
}